package com.ericsson.epc.modules.kpi.thread.ims;

import com.ericsson.common.util.AviatorUtil;
import com.ericsson.common.util.FormulaConvert;
import com.ericsson.common.util.SpringUtils;
import com.ericsson.common.util.UncompressFileGZIPUtil;
import com.ericsson.epc.modules.kpi.entity.Formula;
import com.ericsson.epc.modules.kpi.entity.KpiDataResult;
import com.ericsson.epc.modules.kpi.entity.MeasInfo;
import com.ericsson.epc.modules.kpi.entity.MeasValue;
import com.ericsson.epc.modules.kpi.service.KpiFileProcess;
import com.ericsson.epc.modules.sys.entity.EPCNetElement;
import com.ericsson.epc.modules.sys.entity.IMSNetElement;
import com.googlecode.aviator.Expression;
import com.ice.tar.TarInputStream;
import org.slf4j.Logger;
import org.springframework.data.mongodb.core.MongoTemplate;

import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;

/**
 * IMSKPI数据处理线程
 */
public class KpiDataProcessImsThread implements Runnable {

    private KpiFileProcess kpiFileProcess;
    private Logger log;
    private static final String EXT_GZ = ".gz";
    private static final String EXT_TAR = ".tar";
    private MongoTemplate mongoTemplate;
    private List<Formula> formulas;
    private String typeStr;
    private Date date;
    private IMSNetElement imsNetElement;
    private String imskpiDownloadDir;
    private List<String> formulaUnit;
    private Map<String,IMSNetElement> imsNetElementMap;
    /**
     * 编译后的公式表达式对象缓存
     */
    private Map<Long, Expression> formulaExpressions;

    public KpiDataProcessImsThread(IMSNetElement imsNetElement, Map<Long, Expression> formulaExpressions, String typeStr, List<Formula> formulas, Date date, Logger log, String imskpiDownloadDir, List<String> formulaUnit, Map<String,IMSNetElement> imsNetElementMap) {
        this.kpiFileProcess = SpringUtils.getBean("kpiFileProcess" + typeStr + "Impl");
        this.mongoTemplate = (MongoTemplate) SpringUtils.getBean("mongoTemplate");
        this.imsNetElement = imsNetElement;
        this.formulaExpressions = formulaExpressions;
        this.typeStr = typeStr;
        this.formulas = formulas;
        this.date = date;
        this.log = log;
        this.imskpiDownloadDir=imskpiDownloadDir;
        this.formulaUnit=formulaUnit;
        this.imsNetElementMap=imsNetElementMap;
    }

    @Override
    public void run() {
        Object curDataObj = getData(0, this.imsNetElement);
        countAndInsertToDB(curDataObj);
    }

    private Object getData(int delay, IMSNetElement imsNetElement) {
        try {
            String filePathString = this.imskpiDownloadDir + File.separator + this.typeStr+File.separator;
            List<File> files = downloadFilesByFTP(imsNetElement, delay,filePathString);
            if (files != null && files.size() > 0) {
                // 需要解压的网元类型
                if (kpiFileProcess.needUncompress()) {
                    this.uncompress(files, filePathString);
                }
                // 过滤掉压缩格式文件，逐个解析文件并返回对象
                return filterAndGetData(filePathString);

            } else {
                log.info(" null");
            }
        } catch (Exception e) {
            log.error("KpiDataProcessTask getData method:" + e.getMessage() + "netType is :" + this.typeStr ,e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从ftp服务器下载文件
     *
     * @param imsNetElement
     * @param delay
     * @return
     * @throws Exception
     */
    private List<File> downloadFilesByFTP(IMSNetElement imsNetElement, int delay,String filePathString) throws Exception {
        File filePath = new File(filePathString);
        // 删除上一批次下载的文件
        if (filePath.exists()) {
            File[] oldxmlTargetFiles = filePath.listFiles();
            for (File file : oldxmlTargetFiles) {
                if (file.exists() && file.isFile()) {
                    log.info("|||||||||||||||||||||||||||||||||||||||||||||||"+file.getName());
                    file.delete();
                }
            }
        }
        List<File> files = kpiFileProcess.download(imsNetElement, filePathString, date, delay, log,typeStr);
        return files;
    }

    /**
     * 解压缩下载的文件
     *
     * @param listFiles
     */
    private void uncompress(List<File> listFiles, String path) {
        log.info("==========================  uncompress start  =========================");
        InputStream inputstream = null;
        OutputStream outputstream = null;
        TarInputStream zis = null;
        GZIPInputStream gzis = null;
        try {
            for (int i = 0; i < listFiles.size(); i++) {
                File file = listFiles.get(i);
                if (file.getName().endsWith(".tar")) {
                    File tempFile = null;
                    inputstream = new FileInputStream(file);
                    zis = new TarInputStream(inputstream);
                    while (zis.getNextEntry() != null) {
                        tempFile = new File(path);
                        tempFile.createNewFile();
                        outputstream = new FileOutputStream(tempFile);
                        byte[] buffer = new byte[1024];
                        int len = 0;
                        while ((len = zis.read(buffer)) > 0) {
                            outputstream.write(buffer, 0, len);
                        }
                    }
                } else if (file.getName().endsWith(EXT_GZ)) {
                    log.info("==========================  uncompress name:"+file.getName());
                    UncompressFileGZIPUtil.doUncompressFile(path, file, file.getName());
                }
            }
        } catch (FileNotFoundException e) {
            log.info(">> AnalyticalXMLServiceImpl uncompress failre.Cause by" + e.getMessage());
        } catch (IOException e) {
            log.info(">> AnalyticalXMLServiceImpl uncompress failre.Cause by" + e.getMessage());
        } finally {
            try {
                if (outputstream != null) {
                    outputstream.flush();
                    outputstream.close();
                }
                if (inputstream != null) {
                    inputstream.close();
                }
                if (zis != null) {
                    zis.close();
                }
                if (gzis != null) {
                    gzis.close();
                }
                log.info("==========================  uncompress end  =========================");
            } catch (Exception e) {
                log.info(">> AnalyticalXMLServiceImpl uncompress failre.Cause by" + e.getMessage());
            }
        }
    }

    /**
     * 通过各个kpiFileProcess的实现类的analysis方法解析文件
     * @param path
     * @return
     */
    private Object filterAndGetData(String path){
        File file = new File(path);
        String[] dir = file.list();
        if (dir != null) {
            for (int i = 0; i < dir.length; i++) {
                if (!(dir[i].endsWith(EXT_GZ)) && !(dir[i].endsWith(EXT_TAR))) {
                    return kpiFileProcess.analysis(path + dir[i], log,this.formulaUnit);
                }
            }
        }
        return null;
    }

    private void countAndInsertToDB(Object curDataObj) {
        if(curDataObj == null){
            return;
        }
        Map<String,KpiDataResult> results=new HashMap<>();
            List<MeasInfo> measInfos = (List<MeasInfo>) curDataObj;
            String beginTime = measInfos.get(0).getBeginTime();
            //循环每一个网元
            for (MeasInfo m : measInfos) {
                KpiDataResult kpiDataResult = new KpiDataResult();
                Map<String, String> resultMap = new HashMap<>();
                try {
                    for (Formula formula : formulas) {
                        try {
                            //1 获取编译后的表达式对象
                            Expression compiledExp = formulaExpressions.get(formula.getId());
                            //2 取出计算因子
                            List<String> vars = compiledExp.getVariableFullNames();
                            Map<String, MeasValue> measValueMap = m.getMeasValueMap();
                            Map<String, String> measTypeMap = m.getMeasTypeMap();
                            //计算公式用的map,key 为计算因子，value 为 对应的值
                            Map<String, Object> dataMap = new HashMap<>();
                            for (String var : vars) {
                                String perVar = FormulaConvert.restoreFormula(var);
                                String i = measTypeMap.get(perVar);
                                MeasValue measValue = measValueMap.get(i);
                                if (measValue.isCv() != true) {
                                    dataMap.put(var, Double.valueOf(measValue.getVMap().get(i)));
                                }
                            }
                            Object result = AviatorUtil.execute(compiledExp, dataMap, formula);
                            resultMap.put(String.valueOf(formula.getId()), String.valueOf(result));
                            // System.out.println(formula.getName()+":"+result);
                        } catch (Exception ex) {

                        }
                    }
                } catch (Exception e) {

                }
                IMSNetElement imsNetElement=this.imsNetElementMap.get(m.getDn());
                if (null != imsNetElement) {
                    if (results.containsKey(m.getDn())) {
                        results.get(m.getDn()).getKpiMap().putAll(resultMap);
                    } else {
                        kpiDataResult.setDateTime(beginTime);
                        kpiDataResult.setNetid(String.valueOf(imsNetElement.getId()));
                        kpiDataResult.setPoolid(String.valueOf(imsNetElement.getFnid()));
                        kpiDataResult.setNetName(imsNetElement.getFname());
                        kpiDataResult.setKpiMap(resultMap);
                        results.put(m.getDn(), kpiDataResult);
                    }
                } else {
                    log.info("DN 与网元表映射 失败  DN:" + m.getDn());
                }
            }
        for(KpiDataResult value :results.values()){
            log.info("insert data to MongoDB " + typeStr + " start ...");
            mongoTemplate.insert(value, "imskpi_" + typeStr.toLowerCase());
            log.info("insert data to MongoDB " + typeStr + " end ...");
        }
    }
}
